#!/usr/local/bin/python2.5

_Copyright = "Copyright @ 2010 Michael P. Reilly. All rights reserved."

_SCM_ID = "$Id: reqhandler.py 92 2010-12-18 13:58:51Z arcege@gmail.com $"

import os
import urllib
from sys import exc_info
from traceback import format_exception
from google.appengine.api import users
from google.appengine.ext import webapp
from google.appengine.ext.webapp import template
from database import OSDBLabels, OSDBUser
from tools import send_admin_mail

basedir = os.path.dirname(os.path.dirname(__file__))

__all__ = [
  'TemplateValues',
  'MainRequestHandler',
  'UserRequestHandler',
  'AdminRequestHandler',
  'update_image_md5',
  'valid_name',
]

class TemplateValues(dict):
    def extend(self, dict):
        for (key, value) in dict.items():
            self[key] = value

class BaseRequestHandler(webapp.RequestHandler):
    template_name = None
    help_url = None
    class NotFound(Exception):
        pass
    class Redirect(Exception):
        pass
    class PermRedirect(Redirect):
        pass
    def __init__(self, *args):
        super(BaseRequestHandler, self).__init__(*args)
        self.vars = TemplateValues()

    def get(self, *args):
        try:
            self.init()
        except self.Redirect, e:
            perm = isinstance(e, self.PermRedirect)
            uri = e[0]
            self.redirect(uri, permanent=perm)
            return
        # retrieve messages from previous page for display
        for msg in self.request.get_all('msg'):
            m, c = msg.split('|')
            self.vars['messages'].append(Msg(m, c))
        try:
            self.process_request(*args)
        except self.NotFound:
            self.error(404)
        except ValueError:
            self.error(500)
        except self.Redirect, e:
            perm = isinstance(e, self.PermRedirect)
            uri = e[0]
            if self.vars['messages']:
                msgs = '&'.join(
                    # separated by a '|'
                    ['msg=%s%%7C%s' %
                            (urllib.quote_plus(m.msg),
                             m.msgclass)
                        for m in self.vars['messages']
                    ]
                )
                uri += '?%s' % msgs
            self.redirect(uri, permanent=perm)
        except:
            c, e, t = exc_info()
            self.handle_error(c, e, t)
        else:
            self.eject_template()
    def post(self, *args):
        try:
            self.init()
        except self.Redirect, e:
            perm = isinstance(e, self.PermRedirect)
            uri = e[0]
            self.redirect(uri, permanent=perm)
            return
        try:
            self.process_request(*args)
        except self.Redirect, e:
            uri = e[0]
            if self.vars['messages']:
                msgs = '&'.join(
                    # separated by a '|'
                    ['msg=%s%%7C%s' %
                            (urllib.quote_plus(m.msg),
                             m.msgclass)
                        for m in self.vars['messages']
                    ]
                )
                uri += '?%s' % msgs
            self.redirect(uri) #(e[0])
        except:
            c, e, t = exc_info()
            self.handle_error(c, e, t)
        else:
            self.eject_template()

    def eject_template(self, output=None):
        if not output:
            output = self.gen_template()
        self.response.out.write(str(output))

    def handle_error(self, klass, exception, traceback):
        strings = format_exception(klass, exception, traceback)
        self.template_dir = os.path.dirname(self.template_dir)
        self.vars['error_messages'] = ''.join(strings)
        self.response.out.write(
            template.render(self.template_file("error"), self.vars)
        )

    def process_request(self, *args):
        pass

    def init(self):
        self.init_user()
        self.init_general()

    def init_general(self):
        self.vars['labellist'] = []
        self.vars['messages'] = []
        # set the help_url to the default value, can be overridden
        if self.help_url:
            self.vars['help_url'] = '/help/%s' % self.help_url
        elif self.template_name:
            self.vars['help_url'] = '/help/%s' % self.template_name
        else:
            self.vars['help_url'] = '/help/main'

    def init_user(self):
        self.user = users.get_current_user()
        self.admin = users.is_current_user_admin()
        self.vars['user'] = self.user
        if self.user:
            self.vars['login_url'] = users.create_logout_url(self.request.uri)
            self.vars['login_text'] = 'Logout'
            self.vars['is_admin'] = self.admin
        else:
            self.vars['login_url'] = users.create_login_url(self.request.uri)
            self.vars['login_text'] = 'Login'

    def gen_template(self, tmplname=None):
        if not tmplname:
            tmplname = self.template_name
        path = self.template_file(tmplname)
        return template.render(path, self.vars)

    def template_file(self, tmplname):
        return os.path.join(self.template_dir, tmplname + '.tmpl')

    def send_msg(self, msg, error=False):
        if error:
            msgclass = 'error'
        else:
            msgclass = 'info'
        self.vars['messages'].append(
            Msg(msg, msgclass)
        )

class Msg:
    def __init__(self, msg, msgclass):
        self.msg = msg
        self.msgclass = msgclass
    def __repr__(self):
        return '<%s %s>' % (self.msgclass.upper(), repr(self.msg))

class MainRequestHandler(BaseRequestHandler):
    template_dir = os.path.join(basedir, 'templates', 'main')

    def init(self):
        self.check_user()
        self.init_user()
        self.init_general()
        self.gen_labellist()

    def gen_labellist(self):
        labels = self.mylabels()
        self.vars['labellist'] = [l.name for l in labels]

    def mylabels(self):
        q = OSDBLabels.all()
        q.filter('author =', self.user)
        return list(q)

    def check_user(self):
        user = users.get_current_user()
        if user:
            query = OSDBUser.all()
            query.filter('author =', user)
            c = query.count()
            if c == 0:
                raise self.Redirect('/user/new')
            elif c > 1:
                send_admin_mail(
                    'Multiple_user_error',
                    """\
Hello Admins,

The is a problem with the database; multiple user entries have been identified
with the same Google User id.
%(info)s
""" % {'info': user.nickname()}
                )

class UserRequestHandler(BaseRequestHandler):
    template_dir = os.path.join(basedir, 'templates', 'user')

    def retrieve_user(self, uri='/user'):
        q = OSDBUser.all()
        q.filter('author =', self.user)
        c = q.count()
        if c == 0:
            self.send_msg(
                'no user %s' % repr(self.user.nickname()),
                error=True
            )
            raise self.Redirect(uri)
        elif c > 1:
            self.send_msg(
                'more than one user entry %s' %
                    repr(self.user.nickname()),
                error=True
            )
            raise self.Redirect(uri)
        return q.get()

class AdminRequestHandler(BaseRequestHandler):
    template_dir = os.path.join(basedir, 'templates', 'admin')

class XmlHttpRequestHandler(BaseRequestHandler):
    template_dir = None
    xmlhttpoutput = ''
    def eject_template(self, output=None):
        if not output:
            output = self.xmlhttpoutput
        self.response.headers.add_header('Content-Type', 'application/xml')
        self.response.out.write(str(output))

class HelpRequestHandler(BaseRequestHandler):
    template_dir = os.path.join(basedir, 'templates', 'help')

